# -*- coding: UTF-8 -*-

import sys
import configparser
import os

from addon_manager.addon_venvwrapper import VenvWrapper
from addon_manager.addon_logger import AddOnLogger


class RequirementMgrException(Exception):

    def __init__(self, reason=""):
        Exception.__init__(self, reason)
        self.reason = reason


class ConfParserException(RequirementMgrException):
    pass


class ConfParserNoReqSecException(ConfParserException):
    pass


class RequirementListParserException(RequirementMgrException):
    pass


class RequirementInstallerException(RequirementMgrException):
    pass


class Requirement(object):

    def __init__(self, name, version):
        self.name = name.strip()
        self.version = version.strip()

    def __str__(self):
        return self.name + "==" + self.version


class ConfParser(configparser.ConfigParser):
    __REQUIREMENT_SEC_KEY = "Requirement"
    __REQUIREMENT_DIR_KEY = "dir"
    __REQUIREMENT_LIST_KEY = "list"

    def __init__(self, confFilepath):
        configparser.ConfigParser.__init__(self)
        # path = os.path.join(confFilepath)
        self.read(confFilepath)

        self.confPath = confFilepath
        self.rootdir = self.BaseDir()

        self.__check_requirement_section()
        dirname = self.__Parse(self.__REQUIREMENT_DIR_KEY)
        listname = self.__Parse(self.__REQUIREMENT_LIST_KEY)
        self.dir = self.__GetPath(dirname)
        self.list = self.__GetPath(listname)

    def __check_requirement_section(self):
        if not self.has_section(self.__REQUIREMENT_SEC_KEY):
            reason = "configure file has no " + self.__REQUIREMENT_SEC_KEY + " section !"
            raise ConfParserNoReqSecException(reason)

    def __Parse(self, key):
        try:
            ret = self.get(self.__REQUIREMENT_SEC_KEY, key)
        except configparser.Error:
            reason = "parse " + self.__REQUIREMENT_SEC_KEY + " failed !\n"
            raise ConfParserException(reason)
        else:
            return ret

    def BaseDir(self):
        return os.path.dirname(self.confPath)

    def __GetPath(self, name):
        return os.path.join(self.rootdir, name)

    def ListFilePath(self):
        return self.list

    def ArchivesPath(self):
        return self.dir


class RequirementListParser(object):

    def __init__(self, listpath):
        reqlines = self.__Read(listpath)
        reqInfoList = []
        for line in reqlines:
            reqInfoList.append(self.__ParseLine(line))
        self.reqInfoList = reqInfoList

    def __Read(self, listpath):
        try:
            with open(listpath) as listfile:
                reqStrlist = listfile.readlines()
        except IOError:
            reason = "read " + listpath + " failed !"
            raise RequirementListParserException(reason)

        return reqStrlist

    def __ParseLine(self, line):
        name, version = line.split("==")
        return Requirement(name, version)

    def GetReqInfoList(self):
        return self.reqInfoList


class RequirementInstaller(object):

    def __init__(self, venvWrapper, archiveDir):
        self.archiveDir = archiveDir
        self.venvWrapper = venvWrapper

    def __Install(self, req):
        venvWrapper = self.venvWrapper
        cli_args = [venvWrapper.GetPip(), "install", str(req), "--no-index", "-f", self.archiveDir, "--no-cache-dir"]
        res = os.system(" ".join(cli_args))
        if res:
            reason = "pip install " + str(req) + " failed !"
            raise RequirementInstallerException(reason)

    def Install(self, *reqList):
        for req in reqList:
            self.__Install(req)


class RequirementImporter(object):

    def __init__(self, config):
        self.config = ConfParser(config)
        self.venvWrapper = VenvWrapper(self.config.BaseDir())
        self.venvWrapper.CreateVenv()

        self.requireListParser = RequirementListParser(self.config.ListFilePath())
        self.installer = RequirementInstaller(self.venvWrapper, self.config.ArchivesPath())

    def StartImport(self):
        self.__InstallRequirement()

    def __InstallRequirement(self):
        reqList = self.requireListParser.GetReqInfoList()
        self.installer.Install(*reqList)


class RequirementMgr(object):
    SUCCESS = 0
    FAIL = 1

    def __init__(self):
        pass

    @staticmethod
    def StartImport(config):
        """
        import requirement from addon requirement.list
        """
        try:
            reqImporter = RequirementImporter(config)
            reqImporter.StartImport()
        except ConfParserNoReqSecException as e:
            # no requirement section could be considered
            # no package need to be imported !
            AddOnLogger().error(type(e).__name__ + ":" + e.reason)
            return RequirementMgr.SUCCESS
        except RequirementMgrException as e:
            AddOnLogger().error(str(type(e).__name__) + ":" + e.reason)
            return RequirementMgr.FAIL
        else:
            return RequirementMgr.SUCCESS


__all__ = {"RequirementMgr"}

if __name__ == "__main__":
    # just for test

    def main(config):
        return RequirementMgr.StartImport(config)

    try:
        sys.exit(main(config="/home/jakauser/Documents/read_io/read_io_config.ini"))
    except SystemExit as e:
        print("SystemExit res: " + str(e))
